package juc.Lock.readwriteLock;

import lombok.extern.slf4j.Slf4j;

import javax.xml.crypto.Data;
import java.util.concurrent.locks.StampedLock;

import static juc.Sleep.sleep;

/**
 * @author 况祥彬
 * @date 2020/12/15 12:12
 **/
@Slf4j(topic = "c.TestStampedLock")
public class TestStampedLock {
    public static void main(String[] args) {
        DataContainerStamped dataContainer = new DataContainerStamped(1);
        new Thread(() -> {
            System.out.println("t1读到的数据："+dataContainer.read(1));
        }, "t1").start();
        sleep(0.5);
        new Thread(() -> {
            dataContainer.write(0);
        }, "t2").start();
    }
}

@Slf4j(topic = "c.DataContainerStamped")
class DataContainerStamped {
    private int data;
    private final StampedLock lock = new StampedLock();

    public DataContainerStamped(int data) {
        this.data = data;
        System.out.println("初始数据值为："+data);
    }

    public int read(int readTime) {
        long stamp = lock.tryOptimisticRead();//尝试获取乐观读锁
        log.debug("optimistic read locking...{}", stamp);
        sleep(readTime);
        if (lock.validate(stamp)) //判断data值是否被写锁更改
        {
            log.debug("read finish...{}, data:{}", stamp, data);
            return data;
        }
        //已经进入写模式，没办法只能老老实实的获取读锁
        // 锁升级 - 读锁
        log.debug("数据被修改 updating to read lock... {}", stamp);
        try {
            stamp = lock.readLock();
            log.debug("read lock {}", stamp);
            sleep(readTime);
            return data;//成功获取到读锁，并重新获取最新的变量值
        } finally {
            log.debug("read unlock {}", stamp);
            lock.unlockRead(stamp);
        }
    }

    public void write(int newData) {
        long stamp = lock.writeLock();
        log.debug("write lock {}", stamp);
        try {
            sleep(2);
            System.out.println("t2写入数据 "+newData);
            this.data = newData;
        } finally {
            log.debug("write unlock {}", stamp);
            lock.unlockWrite(stamp);
        }
    }
}

